package com.jjc.android.activity

import android.content.Intent
import android.content.SharedPreferences
import android.hardware.camera2.CameraAccessException
import android.hardware.camera2.CameraCharacteristics
import android.hardware.camera2.CameraManager
import android.hardware.camera2.CameraMetadata
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.text.TextUtils
import android.util.Pair
import android.util.Range
import android.view.View
import android.widget.Button
import android.widget.TextView
import com.jjc.android.GlobalManager
import com.jjc.android.R
import com.jjc.android.base.BaseActivity
import com.jjc.android.util.Common.getExposureTimeString
import com.jjc.android.util.id

class ProbeActivity : BaseActivity() {
    var manager: CameraManager? = null
    var characteristics: CameraCharacteristics? = null
    var prefs: SharedPreferences? = null
    var tv: TextView? = null
    var result = "Probing..."
    var result_mail = ""
    var fpos = "<font style=\"color:#00aa00;\">"
    var fneg = "<font style=\"color:#990000;\">"
    var check = "<div style=\"float:left;width:20px;color:#00aa00;\">&#x2713;</div>"
    var cross = "<div style=\"float:left;width:20px;color:#990000;\">&#x2717;</div>"
    private val btn_send:Button by id<Button>(R.id.btn_send)

    override val layoutId: Int = R.layout.activity_probe

    override fun initView(savedInstanceState: Bundle?) {
        btn_send.setOnClickListener {
            val emailIntent = Intent(
                Intent.ACTION_SENDTO, Uri.fromParts(
                    "mailto", "weis.tobi+camera2@gmail.com", null
                )
            )
            emailIntent.putExtra(Intent.EXTRA_SUBJECT, "Camera2 Supported Features")
            emailIntent.putExtra(Intent.EXTRA_TEXT, result_mail)
            startActivity(Intent.createChooser(emailIntent, "Send email..."))
        }
        tv = findViewById(R.id.textview_probe)
        //        tv.loadData(result, "text/html", "utf-8");
        manager = getSystemService(CAMERA_SERVICE) as CameraManager
        val cameraId: String? = runCatching {
            manager!!.cameraIdList[0]
        }.getOrNull()
        characteristics = runCatching {
            manager?.getCameraCharacteristics(cameraId!!)
        }.getOrNull()
        startProbe()
    }

    private fun startProbe() {
        result = ""
        model()
        general()
        ae()
        af()
        awb()
        check_raw()
        //        tv.loadData(result_mail, "text/html", "utf-8");
        tv!!.text = result_mail
        btn_send!!.isEnabled = true
    }

    private fun model() {
        result += "<b>Model</b><br>"
        result += "Model: " + Build.MODEL + "<br>"
        result += "Manufacturer: " + Build.MANUFACTURER + "<br>"
        result += "Build version: " + Build.VERSION.RELEASE + "<br>"
        result += "SDK version: " + Build.VERSION.SDK_INT + "<br>"
        result_mail += """
               DeviceInfo:${GlobalManager.deviceInfo()}
               
               """.trimIndent()
        result_mail += """
               Model:${Build.MODEL}
               
               """.trimIndent()
        result_mail += """
               Manufacturer:${Build.MANUFACTURER}
               
               """.trimIndent()
        result_mail += """
               Build:${Build.VERSION.RELEASE}
               
               """.trimIndent()
        result_mail += """
               SDK:${Build.VERSION.SDK_INT}
               
               """.trimIndent()
    }

    protected var exposureTimeRange: Range<Long>? = null
    protected var isoRange: Range<Int>? = null
    private fun check_raw() {
        result += "<br><b>RAW capture</b><br>"
        var isSupportDNG = false
        if (contains(
                characteristics!!.get(
                    CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES
                ),
                CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_RAW
            )
        ) {
            isSupportDNG = true
            result += check + fpos + "RAW capture available</font><br style=\"clear:both;\">"
            result_mail += """
                RawCapture:1
                
                """.trimIndent()
        } else {
            result += cross + fneg + "RAW capture NOT available</font><br style=\"clear:both;\">"
            result_mail += """
                RawCapture:0
                
                """.trimIndent()
        }
        exposureTimeRange =
            characteristics!!.get(CameraCharacteristics.SENSOR_INFO_EXPOSURE_TIME_RANGE)
        isoRange = characteristics!!.get(CameraCharacteristics.SENSOR_INFO_SENSITIVITY_RANGE)
        if (exposureTimeRange != null) {
            result_mail += "exposureTimeRange:" + getExposureTimeString(exposureTimeRange!!.lower) + "-" + getExposureTimeString(
                exposureTimeRange!!.upper
            ) + "\n"
        }
        if (isoRange != null) {
            result_mail += """
                isoRange:${isoRange!!.lower}-${isoRange!!.upper}
                
                """.trimIndent()
        }
        val availableFocalLengths = characteristics!!.get<FloatArray>(CameraCharacteristics.LENS_INFO_AVAILABLE_FOCAL_LENGTHS)
        if(availableFocalLengths!=null){
            availableFocalLengths.joinToString("/"){
                it.toString()
            }
            result_mail += "FocalLengths:"+availableFocalLengths.joinToString {
                it.toString()
            }
        }
        //        if(!isSupportDNG){
//            String value = null;
//            int i = value.length();
//        }
    }

    private fun general() {
        result += "<br><b>Hardware Level Support Category</b><br>"
        val mylevel = characteristics!!.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL)
        val levels: MutableList<Pair<*, *>> = ArrayList()
        levels.add(Pair(CameraMetadata.INFO_SUPPORTED_HARDWARE_LEVEL_3, "Level_3"))
        levels.add(Pair(CameraMetadata.INFO_SUPPORTED_HARDWARE_LEVEL_FULL, "Full"))
        levels.add(Pair(CameraMetadata.INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED, "Limited"))
        levels.add(Pair(CameraMetadata.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY, "Legacy"))

        /*
        Log.d("SL:", "Full:"+INFO_SUPPORTED_HARDWARE_LEVEL_FULL);
        Log.d("SL:", "Limited:"+INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED);
        Log.d("SL:", "Legacy:"+INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY);
        Log.d("SL:", "Level3:"+INFO_SUPPORTED_HARDWARE_LEVEL_3);
        */result_mail += "SupportLevel:$mylevel\n"
        for (l in levels) {
            if (l.first === mylevel) {
                result += check + fpos + l.second + "</font><br style=\"clear:both;\">"
                result_mail += """
                    SupportLevel HR:${l.second}
                    
                    """.trimIndent()
            } else {
                result += cross + fneg + l.second + "</font><br style=\"clear:both;\">"
            }
        }
    }

    private fun awb() {
        result += "<br><b>Whitebalance</b><br>"
        val ml: MutableList<Pair<Int, String>> = ArrayList()
        ml.add(Pair(CameraMetadata.CONTROL_AWB_MODE_OFF, "Whitebalance off"))
        ml.add(Pair(CameraMetadata.CONTROL_AWB_MODE_AUTO, "Automatic whitebalance"))
        ml.add(Pair(CameraMetadata.CONTROL_AWB_MODE_CLOUDY_DAYLIGHT, "WB: cloudy day"))
        ml.add(Pair(CameraMetadata.CONTROL_AWB_MODE_DAYLIGHT, "WB: day"))
        ml.add(Pair(CameraMetadata.CONTROL_AWB_MODE_FLUORESCENT, "WB: fluorescent"))
        ml.add(Pair(CameraMetadata.CONTROL_AWB_MODE_INCANDESCENT, "WB: incandescent"))
        ml.add(Pair(CameraMetadata.CONTROL_AWB_MODE_SHADE, "WB: shade"))
        ml.add(Pair(CameraMetadata.CONTROL_AWB_MODE_TWILIGHT, "WB: twilight"))
        ml.add(Pair(CameraMetadata.CONTROL_AWB_MODE_WARM_FLUORESCENT, "WB: warm fluorescent"))
        val tmp = characteristics!!.get(CameraCharacteristics.CONTROL_AWB_AVAILABLE_MODES)
        val aelist: MutableList<Int> = ArrayList()
        for (index in tmp!!.indices) {
            aelist.add(tmp[index])
        }
        for (kv in ml) {
            if (aelist.contains(kv.first)) {
                result += check + fpos + kv.second + "</font><br style=\"clear:both;\">"
                result_mail += kv.second.toString() + ":" + 1 + "\n"
            } else {
                result_mail += kv.second.toString() + ":" + 0 + "\n"
                result += cross + fneg + kv.second + "</font><br style=\"clear:both;\">"
            }
        }
        try {
            if (characteristics!!.get(CameraCharacteristics.CONTROL_AWB_LOCK_AVAILABLE)!!) {
                result += check + fpos + "AWB Lock" + "</font><br style=\"clear:both;\">"
                result_mail += """
                    AWB Lock:1
                    
                    """.trimIndent()
            } else {
                result_mail += """
                    AWB Lock:0
                    
                    """.trimIndent()
                result += cross + fneg + "AWB Lock" + "</font><br style=\"clear:both;\">"
            }
        } catch (e: Exception) {
        }
    }

    private fun af() {
        result += "<br><b>Focus</b><br>"
        // not able to get the enum/key names from the ints,
        // so I am doing it myself
        val ml: MutableList<Pair<Int, String>> = ArrayList()
        ml.add(Pair(CameraMetadata.CONTROL_AF_MODE_OFF, "Manual focus"))
        ml.add(Pair(CameraMetadata.CONTROL_AF_MODE_AUTO, "Auto focus"))
        ml.add(Pair(CameraMetadata.CONTROL_AF_MODE_MACRO, "Auto focus macro"))
        ml.add(
            Pair(
                CameraMetadata.CONTROL_AF_MODE_CONTINUOUS_PICTURE,
                "Auto focus continuous picture"
            )
        )
        ml.add(Pair(CameraMetadata.CONTROL_AF_MODE_CONTINUOUS_VIDEO, "Auto focus continuous video"))
        ml.add(Pair(CameraMetadata.CONTROL_AF_MODE_EDOF, "Auto focus EDOF"))
        val tmp = characteristics!!.get(CameraCharacteristics.CONTROL_AF_AVAILABLE_MODES)
        val aelist: MutableList<Int> = ArrayList()
        for (index in tmp!!.indices) {
            aelist.add(tmp[index])
        }
        for (kv in ml) {
            if (aelist.contains(kv.first)) {
                result += check + fpos + kv.second + "</font><br style=\"clear:both;\">"
                result_mail += kv.second + ":" + 1 + "\n"
            } else {
                result += cross + fneg + kv.second + "</font><br style=\"clear:both;\">"
                result_mail += kv.second + ":" + 0 + "\n"
            }
        }
    }

    private fun ae() {
        result += "<br><b>Exposure</b><br>"
        // not able to get the enum/key names from the ints,
        // so I am doing it myself
        val ml: MutableList<Pair<Int, String>> = ArrayList()
        ml.add(Pair(CameraMetadata.CONTROL_AE_MODE_OFF, "Manual exposure"))
        ml.add(Pair(CameraMetadata.CONTROL_AE_MODE_ON, "Auto exposure"))
        ml.add(Pair(CameraMetadata.CONTROL_AE_MODE_ON_ALWAYS_FLASH, "Auto exposure, always flash"))
        ml.add(Pair(CameraMetadata.CONTROL_AE_MODE_ON_AUTO_FLASH, "Auto exposure, auto flash"))
        ml.add(
            Pair(
                CameraMetadata.CONTROL_AE_MODE_ON_AUTO_FLASH_REDEYE,
                "Auto exposure, auto flash redeye"
            )
        )
        val tmp = characteristics!!.get(CameraCharacteristics.CONTROL_AE_AVAILABLE_MODES)
        val aelist: MutableList<Int> = ArrayList()
        for (index in tmp!!.indices) {
            aelist.add(tmp[index])
        }
        for (kv in ml) {
            if (aelist.contains(kv.first)) {
                result += check + fpos + kv.second + "</font><br style=\"clear:both;\">"
                result_mail += kv.second + ":" + 1 + "\n"
            } else {
                result += cross + fneg + kv.second + "</font><br style=\"clear:both;\">"
                result_mail += kv.second + ":" + 0 + "\n"
            }
        }
        try {
            if (characteristics!!.get(CameraCharacteristics.CONTROL_AE_LOCK_AVAILABLE)!!) {
                result += check + fpos + "AE Lock" + "</font><br style=\"clear:both;\">"
                result_mail += """
                    AF Lock:1
                    
                    """.trimIndent()
            } else {
                result += cross + fneg + "AE Lock" + "</font><br style=\"clear:both;\">"
                result_mail += """
                    AF Lock:0
                    
                    """.trimIndent()
            }
        } catch (e: Exception) {
        }
    }

    override fun isFullscreenStatus(): Boolean {
        return false
    }

    override fun isStatusWhiteModel(): Boolean {
        return false
    }

    companion object {
        fun contains(modes: IntArray?, mode: Int): Boolean {
            if (modes == null) {
                return false
            }
            for (i in modes) {
                if (i == mode) {
                    return true
                }
            }
            return false
        }
    }
}